package com.shadowtorcher.TableRolePlayingSystem.controller.WebSocket;

import com.shadowtorcher.TableRolePlayingSystem.DataStructure.DataSegment;
import com.shadowtorcher.TableRolePlayingSystem.bean.Map;
import com.shadowtorcher.TableRolePlayingSystem.bean.User;
import com.shadowtorcher.TableRolePlayingSystem.util.Logger;
import com.shadowtorcher.TableRolePlayingSystem.util.Security;
import org.springframework.web.socket.WebSocketSession;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import java.util.HashMap;

public class WebSocketHandShake {
    public static boolean doHandShake(DataSegment dataSegment, WebSocketSession webSocketSession, WebSocketUser webSocketUser, WebSocketPool pool) throws BadPaddingException, IllegalBlockSizeException, InvalidKeySpecException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
        DataSegment logInAns = new DataSegment();
        String step = dataSegment.getString("step");
        switch (step) {
            case "1": {
                assert webSocketUser.status == WebSocketUser.WAITING_TO_HANDSHAKE_STEP1;
                String name = dataSegment.getString("user");
                Logger.debug(WebSocketHandShake.class, "用户", name, "进行认证");
                User user = SaveProcessor.getUserByName(name);
                if (user == null) {
                    logInAns.put("code", "1");
                    logInAns.put("why", "登录失败,用户不存在");
                    webSocketUser.status = WebSocketUser.LOG_FAILURE;
                    WebSocketHandler.send(logInAns, webSocketUser);
                    return false;
                }
                webSocketUser.setUser(user);
                webSocketUser.setSession(webSocketSession);

                logInAns.put("code", "0");
                String random = Security.getRandom();
                Cipher userEncodeCipher = webSocketUser.getUserEncodeCipher();
                logInAns.put("random", Base64.getEncoder().encodeToString(userEncodeCipher.doFinal(random.getBytes())));
                webSocketUser.setRandom(random);
                webSocketUser.status = WebSocketUser.WAITING_TO_HANDSHAKE_STEP2;
                WebSocketHandler.send(logInAns, webSocketUser);
                return false;
            }
            case "2": {
                assert webSocketUser.status == WebSocketUser.WAITING_TO_HANDSHAKE_STEP2;
                String room = dataSegment.getString("room");
                Map gameMap = SaveProcessor.getMapByMapID(room);
                if (room == null || gameMap == null) {
                    logInAns.put("code", "1");
                    logInAns.put("why", "登录失败,房间暗号不存在");
                    webSocketUser.status = WebSocketUser.LOG_FAILURE;
                    WebSocketHandler.send(logInAns, webSocketUser);
                    return false;
                }
                WebSocketRoom gameRoom = roomPool.prepareMap(room);
                if (gameRoom.getUser(webSocketUser.getUserName()) != null) {
                    logInAns.put("code", "1");
                    logInAns.put("why", "登录失败,用户已存在");
                    webSocketUser.status = WebSocketUser.LOG_FAILURE;
                    WebSocketHandler.send(logInAns, webSocketUser);
                    return false;
                }
                String random = dataSegment.getString("random");
                random = new String(Security.getServerDecodeCipher().doFinal(Base64.getDecoder().decode(random)));
                if (random.equals(webSocketUser.getRandom())) {
                    logInAns.put("code", "0");
                    logInAns.put("why", "与服务器链接成功");
                    webSocketUser.status = WebSocketUser.LOG_SUCCESS;
                    webSocketUser.setRoom(gameRoom);
                    webSocketUser.setDm(gameMap.getOwnerName().equals(webSocketUser.getUserName()));
                    gameRoom.addUser(webSocketUser);
                    pool.addNewUser(webSocketUser, gameRoom);
                    Logger.debug(WebSocketHandShake.class, "用户认证成功 " + webSocketUser.getUserName());
                    WebSocketHandler.send(logInAns, webSocketUser);
                } else {
                    logInAns.put("code", "1");
                    logInAns.put("why", "密钥验证失败, 请重新登录");
                    webSocketUser.status = WebSocketUser.LOG_FAILURE;
                    WebSocketHandler.send(logInAns, webSocketUser);
                    return false;
                }
            }
        }
        return true;
    }

    private static class roomPool {
        static HashMap<String, WebSocketRoom> pool = new HashMap<>();

        public static WebSocketRoom prepareMap(String string) {
            WebSocketRoom room = pool.get(string);
            Map gameMap = SaveProcessor.getMapByMapID(string);
            if (room == null) {
                Logger.debug(roomPool.class, "创建房间", string);
                room = new WebSocketRoom(gameMap);
                pool.put(string, room);
            }
            return room;
        }
    }
}
